package controllers;
// This file contains material supporting section 3.7 of the textbook:
// "Object Oriented Software Engineering" and is issued under the open-source
// license found at www.lloseng.com 

import messagesPacks.*;
import ocsf.server.*;
/**
 * This class overrides some of the methods in the abstract 
 * superclass in order to give more functionality to the server.
 *
 * @author Dr Timothy C. Lethbridge
 * @author Dr Robert Lagani&egrave;re
 * @author Fran&ccedil;ois B&eacute;langer
 * @author Paul Holden
 * @version July 2000
 */
public class EchoServer extends AbstractServer 
{
  //Class variables *************************************************
  
  /**
   * The default port to listen on.
   */
  final public static int DEFAULT_PORT = 5555;
  
  private static ServerUIP UIPLayer;
  
  //Constructors ****************************************************
  
  /**
   * Constructs an instance of the echo server.
   *
   * @param port The port number to connect on.
   */
  public EchoServer(int port,ServerUIP suip) 
  {
	  super(port);
	  setUIPLayer(suip); // must find a way to update this before the call to super() 
  }
  
  //Instance methods ************************************************
  
  /**
   * This method handles any messages received from the client.
   *
   * @param msg The message received from the client.
   * @param client The connection from which the message originated.
   */
  public void handleMessageFromClient(Object msg, ConnectionToClient client)
  {
	  GenericMessage rec_msg;
	  // Check type of message
	  rec_msg = (GenericMessage)msg;
	
	  switch(rec_msg.getType())
	  {
		    
	  		case LibrarianGetBookSubjectMSG:
	  		{
	  			UIPLayer.handleLibrarianSubjectBooksRequest(client, (LibrarianSubjectMessage) rec_msg);
	  			break;
	  		}
	  		case LibrarianRemoveCopyMSG:
	  		{
	  			UIPLayer.handleLibrarianRemoveCopyRequest(client, (LibrarianRemoveCopyMessage) rec_msg);
	  			break;
	  		}
	  		case LibrarianEditBookMSG:
			{
				UIPLayer.handleLibrarianEditBookRequest( client , (LibrarianEditBookMessage)rec_msg );
				break;
			}
	  		case LibrarianSearchCopyMSG:
	  		{
	  			LibrarianSearchCopyMessage librarianSearchCopyMessage =(LibrarianSearchCopyMessage)rec_msg;
	    		UIPLayer.handleLibrarianSearchCopyRequest (client,librarianSearchCopyMessage.getCopy().getCopyID());
	    		break;
	  		}
	  		case LibrarianRemoveBookMSG:
	  		{
	  			UIPLayer.handleLibrarianRemoveBookRequest(client, (LibrarianRemoveBookMessage) rec_msg);
	  			break;
	  		}
	  		case LibrarianReturnBookMSG:
	  		{
	  			UIPLayer.handleLibrarianReturnBookRequest(client, (LibrarianReturnBookMessage) rec_msg);
	  			break;
	  		}
	  		case LibrarianAddCopyMSG:
	  		{
	  			UIPLayer.handleLibrarianAddCopyRequest(client, (LibrarianAddCopyMessage)rec_msg);
	  			break;
	  		}
	  		case LibrarianEditCopyMSG:
	  		{
				UIPLayer.handleLibrarianEditCopyRequest( client , (LibrarianEditCopyMessage)rec_msg );
				break;
	  		}
	  		case LibrarianAddBookMSG:
	  		{
	  			
	  			UIPLayer.handleLibrarianAddBookRequest(client, (LibrarianAddBookMessage)rec_msg);
	  			break;
	  		}
	  		case LibrarianSearchUserMSG:
	    	{
	    		LibrarianSearchUserMessage librarianSearchUserMessage =(LibrarianSearchUserMessage)rec_msg;
	    		UIPLayer.handleLibrarianSearchUserRequest (client,librarianSearchUserMessage.getUser().getID());
	    		break;
	    	}
	    	case OrderBookMSG:
	    	{
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	    	    UIPLayer.handleSubscOrderBookRequest( client , (BookOrderMessage)rec_msg );
	    	    break;
	    	}
	  		case SubscriberSearchBookMSG:
	  		{
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	    	    UIPLayer.handleSubscSearchBookRequest( client , (SubscriberSearchBookMassege)rec_msg );
	    	    break;
	  		}
		  	case SubBorrowMSG:
		  	{
		  		 System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
		  		 UIPLayer.handleSubscExtendRequest( client , (SubscriberBorrowDataMessage)rec_msg );
	  			break;
		  	}
		  	case SubExtendBorrowMSG:
		  	{
		  		 System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
		  		 UIPLayer.handleSubscExtendBorrowRequest( client , (SubExtendBorrowMessage)rec_msg );
	  			break;
		  	}
	  		case ViewHistoryMSG:
	  		{
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	    	    UIPLayer.handleSubsViewHistoryRequest( client , (ViewHistoryMessage)rec_msg );
	    	    break;
	  		}
	  		case SubscUpdateProfileMSG:
	  		{
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	  			UIPLayer.handleSubscUpdateProfileRequest( client , (SubscriberUpdateProfileMessage)rec_msg );
	  			break;
	  		}
	  		case BookSubjectsMSG:
	  		{
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	  			UIPLayer.handleSubjectBooksRequest(client);
	  			break;
	  		}
	  		case SuspendMSG:
	  		{
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	  			UIPLayer.handleSuspendSub(client, (SuspendMSG)rec_msg);
	  			break;
	  		}
	  		case ManagerSerachSubMSG:
	  		{
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	  			UIPLayer.handleManagerSerachSubMSG(client,(ManagerSerachSubMSG)rec_msg);
	  			break;
	  		}
	  		case BorrowStatisticsMSG:
	  		{
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	  			UIPLayer.handleBorrowReportData(client);
	  			break;
	  		}
	  		case ManagerLatenessReportMSG:
	  		{	
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );	
	  			UIPLayer.handleLatenessReport(client);
	  			break;
	  		}
	  		case ActivityMSG:
	  		{
	  			ActivityReportMessage Amsg = (ActivityReportMessage)rec_msg;
	  			System.out.println("EchoServer > got message from Client (Case: "+rec_msg.getType().toString()+")" );
	  			if(Amsg.actionChooser==1)   
	  				    UIPLayer.handleActivityReportRequest(client ,(ActivityReportMessage)rec_msg);
	  			else
	  			if(Amsg.actionChooser==2)
	  				   UIPLayer.handleNewActivityReportRequest(client ,(ActivityReportMessage)rec_msg);

	  			break;
	  		}
	  		case LoginMSG:
	  		{
	  			LoginMessage login_msg = (LoginMessage)rec_msg;
	  			UIPLayer.getUILayer().msgConsole("LOGIN from " + login_msg.getUser());
	  			
	  			// This code is for testing client TIMEOUT. the idea is to delay the answer from the server and
	  			// the clients will activate their timeouts. 
				/*try {
					System.out.println("sleeping 20s ");
					wait(20000);
					System.out.println("sleeping 20s ended");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}*/
	  			
	  			client.setInfo("USER", login_msg.getUser());
	  			UIPLayer.handleLogin(client,login_msg.getUser(), login_msg.getPassword());
	  			break;
	  		}
	  		case LogoutMSG:
	  		{
	  			LogoutMessage logout_msg = (LogoutMessage)rec_msg;
	  			UIPLayer.getUILayer().msgConsole("LOGOUT from " + client.getInfo("USER") + "@" + logout_msg.getIP());		  			
	  			if (UIPLayer.handleLogout(client,"","") == 1)
	  				client.setInfo("USER", "Guest");
	  			break;
	  		}
	  		case Exit:
	  		{
	  			clientDisconnected(client);
	  			break;
	  		}
	  		case UsersMSG:
	  		{
	  			UIPLayer.getUILayer().msgConsole("[UsersMSG] Message received: from " + client);
	  			switch(((UsersMSG)rec_msg).getOp())
	  			{
	  			    case Manager_ViewEmployees:
	  			    {
	  			    	UIPLayer.handleEmployeesList(client);
		  				break;
	  			    }
		  			case ADMIN_unlock:
		  			{
		  				UIPLayer.handleUnlockUser(client, (UsersMSG)rec_msg);
		  				break;
		  			}
		  			case ADMIN_listLocked:
		  			{
		  				UIPLayer.handleListLockedUsers(client);
		  				break;
		  			}
		  			case ADMIN_graduate:
		  			{
		  				UIPLayer.handleGraduateUser(client, (UsersMSG)rec_msg);
		  				break;		  				
		  			}
					case ALL_createUser:
					{
						UIPLayer.handleCreateUser(client, (UsersMSG)rec_msg);
						break;
					}
					
					case EditUser: 
					{
						UIPLayer.handleLibrarianEditUser(client,(UsersMSG)rec_msg);
						System.out.println("Echo Server: Edit User");
						break;
					}
					case Manager_AllUnsuspended:
					{
						UIPLayer.handleUnsuspendedSubs(client);
						break;	
					}
					case Manager_LateSubscribers:
					{  
						UIPLayer.handleLateSubs(client);
						break;
					}
					default:
					{
						break;
					}
	  			}
	  			break;
	  		}
	  		case BorrowMSG:
	  		{
	  			UIPLayer.handleLibrarianBorrowCopy(client, (BorrowMessage)rec_msg);
	  			break;
	  		}
	  		case LibrarianManualExtMSG:
	  		{
	  			UIPLayer.handleLibrarianManualExtension(client, (ManualExtMessage)rec_msg);
	  			break;
	  		}	
	  		case TOCMSG:
	  		{
	  			UIPLayer.handlePdfUpload(client, (TOCMessage)rec_msg);
	  			break;	  			
	  		}
	  		case RequestTOCMSG:
	  		{
	  			UIPLayer.handlePdfDownload(client, (RequestTOCMessage)rec_msg);
	  			break;	  			
	  		}
	  		case DeleteTOCMSG:
	  		{
	  			UIPLayer.handlePdfDelete(client, (DeleteTOCMessage)rec_msg);
	  			break;	  			
	  		}	  
	  		default:
	  		{
  				UIPLayer.getUILayer().msgConsole("[DEFAULT] Message received: from " + client);	  			
	  			System.out.println("[DEFAULT ] Message received: from " + client);
	  		}
	  		
	  } // Switch	
  }

    
  /**
   * This method overrides the one in the superclass.  Called
   * when the server starts listening for connections.
   */
  protected void serverStarted()
  {
    System.out.println
      ("Server listening for connections on port " + getPort());
	if (UIPLayer != null)
		UIPLayer.getUILayer().msgConsole("Server listening for connections on port " + getPort());
  }
  
  /**
   * This method overrides the one in the superclass.  Called
   * when the server stops listening for connections.
   */
  protected void serverStopped()
  {
    System.out.println
      ("Server has stopped listening for connections.");
	if (UIPLayer != null)
		UIPLayer.getUILayer().msgConsole("Server has stopped listening for connections.");
  }
  
  synchronized protected void clientDisconnected(ConnectionToClient client) 
  {
	  if ((client != null) && (UIPLayer.isServerRunning()))
	  {
		  String user = (String) client.getInfo("USER");
		  String ip = (String) client.getInfo("IP");
		  System.out.println("EchoServer: User " + client.getInfo("USER") + "@" + client.getInfo("IP") + " disconnected!");
		  UIPLayer.getUILayer().msgConsole("User " + client.getInfo("USER") + "@" + client.getInfo("IP") + " disconnected!");
		  UIPLayer.handleLogout(client,user,ip);
	  }
	  else if (client == null)
	  {
		  UIPLayer.getUILayer().msgConsole("EchoServer: (clientDisconnected) User disconnected, client is null!");
	  }
	  else
	  {
		  UIPLayer.getUILayer().msgConsole("EchoServer: (clientDisconnected) User disconnected, but server is stopped!");
	  }
  }
  
  protected void clientConnected(ConnectionToClient client) 
{
	  System.out.println("User " + client + " Connected!");
	  client.setInfo("USER", "Guest");
	  client.setInfo("IP", client.getInetAddress().getHostAddress());
	  UIPLayer.getUILayer().msgConsole("User " + client.getInfo("USER") + "@" + client.getInfo("IP") + " Connected!");
}
  //Class methods ***************************************************
  public ServerUIP getUIPLayer() 
  {
		return UIPLayer;
  }


  public void setUIPLayer(ServerUIP uIPLayer) 
  {
		UIPLayer = uIPLayer;
  }


  /**
   * This method is responsible for the creation of 
   * the server instance (there is no UI in this phase).
   *
   * @param args[0] The port number to listen on.  Defaults to 5555 
   *          if no argument is entered.
   */
  public static void main(String[] args) 
  {
	  int port = 0; //Port to listen on

	  try
	  {
		  port = Integer.parseInt(args[0]); //Get port from command line
	  }
	  catch(Throwable t)
	  {
		  port = DEFAULT_PORT; //Set port to 5555
	  }
	  
	  EchoServer sv = new EchoServer(port,null);
    
	  try 
	  {
		  sv.listen(); //Start listening for connections
	  } 
	  catch (Exception ex) 
	  {
		  System.out.println("ERROR - Could not listen for clients!");
		if (UIPLayer != null)
			UIPLayer.getUILayer().msgConsole("ERROR - Could not listen for clients!");
	  }
  }
}
//End of EchoServer class
